<?php
/**
 * File containing the RandomNumberProcessor
 *
 * PHP Version 5
 *
 * @category Processors
 * @package  Processors
 * @author   Martin Schlecht <herrlollinger@gmail.com>
 * @license  MIT License
 * @link     http://code.google.com/p/universal-test-data
 */

/**
 * Processor class "RandomNumberProcessor"
 *
 * Processor which is used to process tags which implements random numbers within the text.
 *
 * @category   Processors
 * @package    Processors
 * @subpackage RandomNumberProcessors
 * @author     Martin Schlecht <herrlollinger@gmail.com>
 * @copyright  see @author
 * @license    MIT License
 * @link       http://code.google.com/p/universal-test-data
 *
 * The followings are the available attributes of the processor class
 * @property string $text, the text which should be processed
 */
class RandomNumberProcessor
{
	private $text;
	
	/**
	 * Processes the given text and replaces the tags with the random values, the values can be repeated n times
	 *
	 * @param String $text, the text to process
	 *
	 * @return String
	 */
	public function process($text) {
		$this->text = $text;
		
		preg_match_all("#\s*{(.*?)}#si", $this->text, $matches);
		
		foreach ($matches[1] AS $m) {
			$randomNumberProcessor = new RandomNumberProcessor;
			$string = "{" . $m . "}";
			$m = explode(":", $m);
			
			/**
			 * {randomNumber:10,5}
			 * Random number between 0 and 10 repeated 5 times
			 */
			if ($m[0] == "randomNumber") {
				$parameter = explode(",", $m[1]);
				
				if (!isset($parameter[0]) || !is_numeric($parameter[0])) {
					$parameter[0] = 1000;
				}
				
				if (!isset($parameter[1]) || !is_numeric($parameter[1])) {
					$parameter[1] = 1;
				}				
				
				$this->text = str_replace($string, $this->manageRepeation($randomNumberProcessor->randomNumber(0, $parameter[0]), $string, $parameter[1]), $this->text);
			}
			
			/**
			 * {randomPointNumber:100,5,5}
			 * Random point number between 0 and 100 with 5 digit behind decimal point, n times repeated
			 */
			if ($m[0] == "randomPointNumber") {
				$parameter = explode(",", $m[1]);
				
				if (!isset($parameter[0]) || !is_numeric($parameter[0])) {
					$parameter[0] = 10;
				}
				
				if (!isset($parameter[1]) || !is_numeric($parameter[1])) {
					$parameter[1] = 5;
				}
				
				if (!isset($parameter[2]) || !is_numeric($parameter[2])) {
					$parameter[2] = 1;
				}
				
				$this->text = str_replace($string, $this->manageRepeation($randomNumberProcessor->randomPointNumber($parameter[0], $parameter[1]), $string, $parameter[2]), $this->text);
			}

			/**
			 * {randomZeroPointNumber:5,4}
			 * Random point number with 5 digit behind decimal point, n times repeated
			 */
			if ($m[0] == "randomZeroPointNumber") {
				$parameter = explode(",", $m[1]);
				
				if (!isset($parameter[0]) || !is_numeric($parameter[0])) {
					$parameter[0] = 5;
				}
				
				if (!isset($parameter[1]) || !is_numeric($parameter[1])) {
					$parameter[1] = 1;
				}
				
				$this->text = str_replace($string, $this->manageRepeation($randomNumberProcessor->randomZeroPointNumber($parameter[0]), $string, $parameter[1]), $this->text);
			}			
			
			/**
			 * {randomNumberWithFixedLenght:5,6}
			 * Random number between 10000 and 99999, n times repeated
			 */
			if ($m[0] == "randomNumberWithFixedLenght") {
				$parameter = explode(",", $m[1]);
				if (!isset($parameter[0]) || !is_numeric($parameter[0])) {
					$parameter[0] = 5;
				}
				
				if (!isset($parameter[1]) || !is_numeric($parameter[1])) {
					$parameter[1] = 1;
				}
				
				$this->text = str_replace($string, $this->manageRepeation($randomNumberProcessor->numberWithFixedLenght($parameter[0]), $string, $parameter[1]), $this->text);
			}
			
			/**
			 * {evenRandomNumber:10,6}
			 * 2, 4, 6, 8, 10, n times repeated
			 */
			if ($m[0] == "evenRandomNumber") {
				$parameter = explode(",", $m[1]);
				if (!isset($parameter[0]) || !is_numeric($parameter[0])) {
					$parameter[0] = 10;
				}
				
				if (!isset($parameter[1]) || !is_numeric($parameter[1])) {
					$parameter[1] = 1;
				}
				
				$this->text = str_replace($string, $this->manageRepeation($randomNumberProcessor->evenRandomNumber(0, $parameter[0]), $string, $parameter[1]), $this->text);
			}
			
			/**
			 * {evenRandomNumberWithFixedLenght:5,6}
			 * Random number between 10000 and 99998, only even numbers, n times repeated
			 */
			if ($m[0] == "evenRandomNumberWithFixedLenght") {
				$parameter = explode(",", $m[1]);
				
				if (!isset($parameter[0]) || !is_numeric($parameter[0])) {
					$parameter[0] = 5;
				}
				
				if (!isset($parameter[1]) || !is_numeric($parameter[1])) {
					$parameter[1] = 1;
				}
				
				$this->text = str_replace($string, $this->manageRepeation($randomNumberProcessor->evenNumberWithFixedLenght($parameter[0]), $string, $parameter[1]), $this->text);
			}
			
			/**
			 * {oddRandomNumber:10,5}
			 * 1, 3, 5, 7, 9, n times repeated
			 */
			if ($m[0] == "oddRandomNumber") {
				$parameter = explode(",", $m[1]);
				
				if (!isset($parameter[0]) || !is_numeric($parameter[0])) {
					$parameter[0] = 10;
				}
				
				if (!isset($parameter[1]) || !is_numeric($parameter[1])) {
					$parameter[1] = 1;
				}
				
				$this->text = str_replace($string, $this->manageRepeation($randomNumberProcessor->oddRandomNumber(0, $parameter[0]), $string, $parameter[1]), $this->text);
			}
			
			/**
			 * {oddRandomNumberWithFixedLenght:5,5}
			 * Random number between 10001 and 99999, only odd numbers, n times repeated
			 */
			if ($m[0] == "oddRandomNumberWithFixedLenght") {
				$parameter = explode(",", $m[1]);
				
				if (!isset($parameter[0]) || !is_numeric($parameter[0])) {
					$parameter[0] = 5;
				}
				
				if (!isset($parameter[1]) || !is_numeric($parameter[1])) {
					$parameter[1] = 1;
				}
				
				$this->text = str_replace($string, $this->manageRepeation($randomNumberProcessor->oddNumberWithFixedLenght($parameter[0]), $string, $parameter[1]), $this->text);
			}
			
			/**
			 * {randomNumberRange:1000,2000, n times repeated}
			 * Random number between 1000 and 2000, n times repeated
			 */
			if ($m[0] == "randomNumberRange") {
				$parameter = explode(",", $m[1]);
				
				if (!isset($parameter[0]) || !is_numeric($parameter[0])) {
					$parameter[0] = 1000;
				}
				
				if (!isset($parameter[1]) || !is_numeric($parameter[1])) {
					$parameter[1] = 2000;
				}
				
				if (!isset($parameter[2]) || !is_numeric($parameter[2])) {
					$parameter[2] = 1;
				}
				
				$this->text = str_replace($string, $this->manageRepeation($randomNumberProcessor->randomNumber($parameter[0], $parameter[1]), $string, $parameter[2]), $this->text);
			}
			
			/**
			 * {negativeRandomNumber:6,5}
			 * Negative random number, n times repeated
			 */
			if ($m[0] == "negativeRandomNumber") {
				$parameter = explode(",", $m[1]);
				
				if (!isset($parameter[0]) || !is_numeric($parameter[0])) {
					$parameter[0] = 1000;
				}
				
				if (!isset($parameter[1]) || !is_numeric($parameter[1])) {
					$parameter[1] = 1;
				}
				
				$this->text = str_replace($string, $this->manageRepeation($randomNumberProcessor->negativeRandomNumber(0, $parameter[0]), $string, $parameter[1]), $this->text);
			}
			
			/**
			 * {negativeRandomNumberWithFixedLenght:5,5}
			 * Negative random number with fixed lenght, n times repeated
			 */
			if ($m[0] == "negativeRandomNumberWithFixedLenght") {
				$parameter = explode(",", $m[1]);
				
				if (!isset($parameter[0]) || !is_numeric($parameter[0])) {
					$parameter[0] = 5;
				}
				
				if (!isset($parameter[1]) || !is_numeric($parameter[1])) {
					$parameter[1] = 1;
				}
				
				$this->text = str_replace($string, $this->manageRepeation($randomNumberProcessor->negativeNumberWithFixedLenght($parameter[0]), $string, $parameter[1]), $this->text);
			}
			
			/**
			 * {negativeEvenRandomNumber:6,5}
			 * Negative even random number, n times repeated
			 */
			if ($m[0] == "negativeEvenRandomNumber") {
				$parameter = explode(",", $m[1]);
				
				if (!isset($parameter[0]) || !is_numeric($parameter[0])) {
					$parameter[0] = 1000;
				}
				
				if (!isset($parameter[1]) || !is_numeric($parameter[1])) {
					$parameter[1] = 1;
				}
				
				$this->text = str_replace($string, $this->manageRepeation($randomNumberProcessor->evenRandomNumber(0, $parameter[0]) * -1, $string, $parameter[1]), $this->text);
			}
			
			/**
			 * {negativeEvenRandomNumberWithFixedLenght:7,5}
			 * Negative even random number with fixed lenght, n times repeated
			 */
			if ($m[0] == "negativeEvenRandomNumberWithFixedLenght") {
				$parameter = explode(",", $m[1]);
				
				if (!isset($parameter[0]) || !is_numeric($parameter[0])) {
					$parameter[0] = 5;
				}
				
				if (!isset($parameter[1]) || !is_numeric($parameter[1])) {
					$parameter[1] = 1;
				}
				
				$this->text = str_replace($string, $this->manageRepeation($randomNumberProcessor->evenNumberWithFixedLenght($parameter[0]) * -1, $string, $parameter[1]), $this->text);
			}
			
			/**
			 * {negativeOddRandomNumber:5,5}
			 * Negative odd random number, n times repeated
			 */
			if ($m[0] == "negativeOddRandomNumber") {
				$parameter = explode(",", $m[1]);
				
				if (!isset($parameter[0]) || !is_numeric($parameter[0])) {
					$parameter[0] = 1000;
				}
				
				if (!isset($parameter[1]) || !is_numeric($parameter[1])) {
					$parameter[1] = 1;
				}
				
				$this->text = str_replace($string, $this->manageRepeation($randomNumberProcessor->oddRandomNumber(0, $parameter[0]) * -1, $string, $parameter[1]), $this->text);
			}
			
			/**
			 * {negativeOddRandomNumberWithFixedLenght:4,5}
			 * Negative odd random number with fixed lenght, n times repeated
			 */
			if ($m[0] == "negativeOddRandomNumberWithFixedLenght") {
				$parameter = explode(",", $m[1]);
				
				if (!isset($parameter[0]) || !is_numeric($parameter[0])) {
					$parameter[0] = 5;
				}
				
				if (!isset($parameter[1]) || !is_numeric($parameter[1])) {
					$parameter[1] = 1;
				}
				
				$this->text = str_replace($string, $this->manageRepeation($randomNumberProcessor->oddNumberWithFixedLenght($parameter[0]) * -1, $string, $parameter[1]), $this->text);
			}
			
			/**
			 * {negativeRandomNumberRangeR:3,7,5}
			 * Negative random number range, n times repeated
			 */
			if ($m[0] == "negativeRandomNumberRange") {
				$parameter = explode(",", $m[1]);
				
				if (!isset($parameter[0]) || !is_numeric($parameter[0])) {
					$parameter[0] = 1000;
				}
				
				if (!isset($parameter[1]) || !is_numeric($parameter[1])) {
					$parameter[1] = 2000;
				}
				
				if (!isset($parameter[2]) || !is_numeric($parameter[2])) {
					$parameter[2] = 1;
				}
				
				$this->text = str_replace($string, $this->manageRepeation($randomNumberProcessor->randomNumber($parameter[0], $parameter[1]) * -1, $string, $parameter[2]), $this->text);
			}
		}
		
		return $this->text;
	}
	
	/**
	 * The method returns a random number within a given range
	 *
	 * @param Integer $min, the minimal value
	 * @param Integer $max, the maximal value
	 *
	 * @return Integer
	 */
	public function randomNumber($min, $max) {
		$number = rand($min, $max);
		
		return $number;
	}
	
	/**
	 * The method returns a random point number within a given range
	 *
	 * @param Integer $head, the lenght of the head of the random point number
	 * @param Integer $tail, the lenght of the tail of the random point number
	 *
	 * @return Float
	 */
	public function randomPointNumber($head, $tail) {
		$pointnumber = $this->numberWithFixedLenght($tail) / $this->numberWithFixedLenght($tail);

		$number = round($this->randomNumber(0, $head-1) + $pointnumber, $tail);
						
		return $number;
	}
	
	/**
	 * The method returns a random point number within a given range. The head is 0
	 *
	 * @param Integer $min, the lenght of the tail
	 *
	 * @return Float
	 */
	public function randomZeroPointNumber($tail) {
		return "0." . $this->numberWithFixedLenght($tail);
	}
	
	/**
	 * The method returns a negative random number within a given range
	 *
	 * @param Integer $min, the minimal value
	 * @param Integer $max, the maximal value
	 *
	 * @return Integer
	 */
	public function negativeRandomNumber($min, $max) {
		$number = $this->randomNumber($min, $max);
		
		return $number * -1;
	}
	
	/**
	 * The method returns a random number with a fixed number of digits
	 *
	 * @param Integer $lenght, the number of digits
	 *
	 * @return Integer
	 */
	public function numberWithFixedLenght($lenght) {
		$min = "1";
		$max = "9";
		
		for ($x = 0; $x < $lenght-1; $x++) {
				$min .= "0";
				$max .= "9";
		}
		
		return rand($min, $max);
	}
	
	/**
	 * The method returns a negative random number with a fixed number of digits
	 *
	 * @param Integer $lenght, the number of digits
	 *
	 * @return Integer
	 */
	public function negativeNumberWithFixedLenght($lenght) {
		$number = $this->numberWithFixedLenght($lenght);
		return $number * -1;
	}
	
	/**
	 * The method returns a even random number within a given range
	 *
	 * @param Integer $min, the minimal value
	 * @param Integer $max, the maximal value
	 *
	 * @return Integer
	 */
	public function evenRandomNumber($min, $max) {
		$number = $this->randomNumber($min, $max);
		
		if ($number % 2 != 0) {
			$number++;
		}
		
		if ($number > $max) {
			$number -= 2;
		}
		
		return $number;
	}
	
	/**
	 * The method returns a even negative random number within a given range
	 *
	 * @param Integer $min, the minimal value
	 * @param Integer $max, the maximal value
	 *
	 * @return Integer
	 */
	public function negativeEvenRandomNumber($min, $max) {
		$number = $this->evenRandomNumber($min, $max);
		
		return $number * -1;
	}
	
	/**
	 * The method returns a even random number with a fixed number of digits
	 *
	 * @param Integer $lenght, the number of digits
	 *
	 * @return Integer
	 */
	public function evenNumberWithFixedLenght($lenght) {
		$number = $this->numberWithFixedLenght($lenght);
		
		if ($number % 2 != 0) {
			$number++;
		}
		
		if (sizeof($number) > $lenght) {
			$number -= 2;
		}
		
		return $number;
	}
	
	/**
	 * The method returns a negative even random number with a fixed number of digits
	 *
	 * @param Integer $lenght, the number of digits
	 *
	 * @return Integer
	 */
	public function negativeEvenNumberWithFixedLenght($lenght) {
		$number = $this->evenRandomNumber($lenght);
		
		return $number * -1;
	}
	
	
	/**
	 * The method returns a odd random number within a given range
	 *
	 * @param Integer $min, the minimal value
	 * @param Integer $max, the maximal value
	 *
	 * @return Integer
	 */
	public function oddRandomNumber($min, $max) {
		$number = $this->evenRandomNumber($min, $max);
		
		$number++;
		
		if ($number > $max) {
			$number -= 2;
		}
		
		return $number;
	}
	
	/**
	 * The method returns a odd negative random number within a given range
	 *
	 * @param Integer $min, the minimal value
	 * @param Integer $max, the maximal value
	 *
	 * @return Integer
	 */
	public function negativeOddRandomNumber($min, $max) {
		$number = $this->evenRandomNumber($min, $max);
		
		$number++;
		
		if ($number > $max) {
			$number -= 2;
		}
		
		return $number * -1;
	}
	
	/**
	 * The method returns a odd random number with a fixed number of digits
	 *
	 * @param Integer $lenght, the number of digits
	 *
	 * @return Integer
	 */
	public function oddNumberWithFixedLenght($lenght) {
		$number = $this->evenNumberWithFixedLenght($lenght);
		
		$number++;
		
		if (sizeof($number) > $lenght) {
			$number -= 2;
		}
		
		return $number;
	}
	
	/**
	 * The method returns a negative odd random number with a fixed number of digits
	 *
	 * @param Integer $lenght, the number of digits
	 *
	 * @return Integer
	 */
	public function negativeOddNumberWithFixedLenght($lenght) {
		$number = $this->evenNumberWithFixedLenght($lenght);
		
		$number++;
		
		if ($number > $max) {
			$number -= 2;
		}
		
		return $number * -1;
	}
	
	/**
	 * Manages the repeation of values
	 * 
	 * @param String $value, the value which should be replaced
	 * @param String $string, the string for the cockie
	 * @param String $times, the number of times the value should be repeated
	 * 
	 * @return String
	 */
	public function manageRepeation($value, $string, $times) {
		$replacement = "";
		
		if (Yii::app()->session[$string . "_times"] >= $times || !isset(Yii::app()->session[$string . "_times"])) {
			Yii::app()->session[$string . "_number"] = $value;
			Yii::app()->session[$string . "_times"] = 1;
							
			$replacement = $value;
		} else {
			$number = Yii::app()->session[$string . "_number"];
			$times = Yii::app()->session[$string . "_times"] + 1;
			
			Yii::app()->session[$string . "_times"] = $times;
			
			$replacement = $number;
		}
		
		Yii::app()->session['resetManager']->add($string . "_number");
		Yii::app()->session['resetManager']->add($string . "_times");
		
		return $replacement;
	}
	
	/**
	 * Prints the documentation
	 *
	 * @return String
	 */
	 public function documentation() {
		return array(
			array('{randomNumber:10,5}', 'Random number between 0 and 10, 5 times repeated'),
			array('{randomPointNumber:100,5,5}', 'Random point number between 0 and 100 with 5 digit behind decimal point, 5 times repeated'),
			array('{randomNumberWithFixedLenght:5,5}', 'Random number between 10000 and 99999, 5 times repeated'),
			array('{evenRandomNumber:10,5}', 'Even random number between 0 and 10 (2, 4, 6, 8, 10), 5 times repeated'),
			array('{evenRandomNumberWithFixedLenght:5,5}', 'Random number between 10000 and 99998, only even numbers, 5 times repeated'),
			array('{oddRandomNumber:10,5}', 'Odd random number between 0 and 10 (1, 3, 5, 7, 9), 5 times repeated'),
			array('{oddRandomNumberWithFixedLenght:5,5}', 'Random number between 10001 and 99999, only odd numbers, 5 times repeated'),
			array('{randomNumberRange:1000,2000,5}', 'Random number between 1000 and 2000, 5 times repeated'),
			array('{negativeRandomNumber:10,5}', 'Random number between 0 and 10, 5 times repeated'),
			array('{negativeRandomNumberWithFixedLenght:5,5}', 'Random number between 10000 and 99999, 5 times repeated'),
			array('{negativeEvenRandomNumber:10,5}', 'Even random number between 0 and -10 (2, 4, 6, 8, 10), 5 times repeated'),
			array('{negativeEvenRandomNumberWithFixedLenght:5,5}', 'Random number between -10001 and -99999, only even numbers, 5 times repeated'),
			array('{negativeOddRandomNumber:5,5}', 'Odd random number between 0 and -10 (1, 3, 5, 7, 9), 5 times repeated'),
			array('{negativeOddRandomNumberWithFixedLenght:5,5}', 'Random number between -10001 and -99999, only odd numbers, 5 times repeated'),
			array('{negativeRandomNumberRange:1000,2000,5}', 'Random number between -1000 and -2000, 5 times repeated')
		);

	 }
	 
	 	/**
	 * Prints the documentation
	 *
	 * @return string
	 */
	public function print_documentation() {
		foreach ($this->documentation() AS $docu) {
			echo '<span style="font-family:monospace;font-size:11px">' . $docu[0] . '</span><br/>' . $docu[1] . '<br/>';
		}
	}
}
?>